﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace SmartMathLibrary.NumericalIntegration
{
    /// <summary>
    /// Describes the Gauss-Kronrod rule to use.
    /// </summary>
    public enum GaussKronrodIntegrationMethod
    {
        /// <summary>
        /// Describes a numerical integrator that uses a 15 point Gauss-Kronrod rule.
        /// </summary>
        GaussKronrod15 = 1,
        /// <summary>
        /// Describes a numerical integrator that uses a 21 point Gauss-Kronrod rule.
        /// </summary>
        GaussKronrod21 = 2,
        /// <summary>
        /// Describes a numerical integrator that uses a 31 point Gauss-Kronrod rule.
        /// </summary>
        GaussKronrod31 = 3,
        /// <summary>
        /// Describes a numerical integrator that uses a 41 point Gauss-Kronrod rule.
        /// </summary>
        GaussKronrod41 = 4,
        /// <summary>
        /// Describes a numerical integrator that uses a 51 point Gauss-Kronrod rule.
        /// </summary>
        GaussKronrod51 = 5,
        /// <summary>
        /// Describes a numerical integrator that uses a 61 point Gauss-Kronrod rule.
        /// </summary>
        GaussKronrod61 = 6
    }

    /// <summary>
    /// This class represents an abstract layer for all Gauss-Kronrod integrators.
    /// </summary>
    [Serializable]
    public abstract class AbstractGaussKronrodIntegrator
    {
        /// <summary>
        /// The lower value a of the integral.
        /// </summary>
        private double a;

        /// <summary>
        /// The upper value b of the integral.
        /// </summary>
        private double b;

        /// <summary>
        /// The function of the integral.
        /// </summary>
        private IRealFunction function;

        /// <summary>
        /// Saves the absolute error of the numerical integration.
        /// </summary>
        protected double absoluteError;

        /// <summary>
        /// Saves the absolute accuracy of the numerical integration.
        /// </summary>
        protected double absoluteAccuracy;

        /// <summary>
        /// Saves the relative accuracy of the numerical integration.
        /// </summary>
        protected double relativeAccuracy;

        /// <summary>
        /// Saves the needed function evaluations of the numerical integration.
        /// </summary>
        protected double neededFunctionEvaluations;

        /// <summary>
        /// Describes if the numerical integration has a precision error.
        /// </summary>
        protected bool precisionError;

        /// <summary>
        /// Decribes the integration method of the numerical integration.
        /// </summary>
        private GaussKronrodIntegrationMethod integrationMethod;

        /// <summary>
        /// Initializes a new instance of the <see cref="AbstractGaussKronrodIntegrator"/> class.
        /// </summary>
        /// <param name="a">The lower value a of the integral.</param>
        /// <param name="b">The upper value b of the integral.</param>
        /// <param name="function">The function of the integral.</param>
        /// <param name="integrationMethod">The integration method to use.</param>
        protected AbstractGaussKronrodIntegrator(double a, double b, IRealFunction function,
                                                 GaussKronrodIntegrationMethod integrationMethod)
        {
            //if (a > b)
            //{
            //    double temp = a;
            //    a = b;
            //    b = temp;
            //}

            this.a = a;
            this.b = b;
            this.function = function;
            this.integrationMethod = integrationMethod;
        }

        /// <summary>
        /// Gets or sets the lower value a of the integral.
        /// </summary>
        /// <value>The lower value a of the integral.</value>
        public double A
        {
            get { return a; }
            set { a = value; }
        }

        /// <summary>
        /// Gets or sets the upper value b of the integral.
        /// </summary>
        /// <value>The upper value b of the integral.</value>
        public double B
        {
            get { return b; }
            set { b = value; }
        }

        /// <summary>
        /// Gets or sets the function of the integral.
        /// </summary>
        /// <value>The function of the integral.</value>
        public IRealFunction Function
        {
            get { return function; }
            set { function = value; }
        }

        /// <summary>
        /// Gets the absolute error of the numerical integration.
        /// </summary>
        /// <value>The absolute error of the numerical integration.</value>
        public double AbsoluteError
        {
            get { return absoluteError; }
        }

        /// <summary>
        /// Gets the absolute accuracy of the numerical integration.
        /// </summary>
        /// <value>The absolute accuracy of the numerical integration.</value>
        public double AbsoluteAccuracy
        {
            get { return absoluteAccuracy; }
        }

        /// <summary>
        /// Gets the relative accuracy of the numerical integration.
        /// </summary>
        /// <value>The relative accuracy of the numerical integration.</value>
        public double RelativeAccuracy
        {
            get { return relativeAccuracy; }
        }

        /// <summary>
        /// Gets the needed function evaluations of the numerical integration.
        /// </summary>
        /// <value>The needed function evaluations of the numerical integration.</value>
        public double NeededFunctionEvaluations
        {
            get { return neededFunctionEvaluations; }
        }

        /// <summary>
        /// Gets or sets the integration method of the numerical integration.
        /// </summary>
        /// <value>The integration method of the numerical integration.</value>
        public GaussKronrodIntegrationMethod IntegrationMethod
        {
            get { return integrationMethod; }
            set { integrationMethod = value; }
        }

        /// <summary>
        /// Describes if the numerical integration has a precision error. If true the
        /// calculated result may be not correct.
        /// </summary>
        /// <value><c>true</c> if [precision error]; otherwise, <c>false</c>.</value>
        public bool PrecisionError
        {
            get { return precisionError; }
        }
    }
}